package com.ksm.server.service;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import com.ksm.context.BeanProvider;
import com.ksm.service.IDocumentService;

/**
 * Servlet to handle file upload requests
 * 
 * @author sbensadoun
 * 
 */
@Component
public class FileUploadServlet extends HttpServlet implements HttpRequestHandler {

	private static final String DEFAULT_WORKING_DIR = "./file/working";
	private static final SimpleDateFormat FORMAT_DATE = new SimpleDateFormat("yyyyMMddHHmmss");

	@Value("${file.directory.working}")
	public String workingDirectory;

	private final static Logger LOGGER = Logger.getLogger(FileUploadServlet.class);

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		super.doGet(req, resp);
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		LOGGER.debug("Working dir " + workingDirectory);

		IDocumentService documentService = BeanProvider.getBean(IDocumentService.class);

		// process only multipart requests
		if (ServletFileUpload.isMultipartContent(req)) {

			File tempDir = getTempDir();
			if (!tempDir.exists()) {
				tempDir.mkdirs();
			}

			// Create a factory for disk-based file items
			FileItemFactory factory = new DiskFileItemFactory();

			// Create a new file upload handler
			ServletFileUpload upload = new ServletFileUpload(factory);

			// Parse the request
			try {
				List<FileItem> items = upload.parseRequest(req);
				// String typeDocument = null;
				// for (FileItem fileItem : items) {
				// LOGGER.debug("Field : " + fileItem.getFieldName());
				// if (fileItem.getFieldName().equals("firstName")) {
				// typeDocument = fileItem.getString();
				// LOGGER.debug("Type Document : " + typeDocument);
				// }
				// }

				for (FileItem fileItem : items) {

					// process only file upload
					if (!fileItem.isFormField()) {
						LOGGER.debug("Field : " + fileItem.getFieldName());
						String fileName = fileItem.getName();

						// get only the file name not whole path
						if (fileName != null) {
							fileName = FilenameUtils.getName(fileName);
						}

						String fileNameStored = getFileName(fileName);
						File uploadedFile = new File(getWorkingDirectory(), fileNameStored);
						if (uploadedFile.createNewFile()) {
							fileItem.write(uploadedFile);
							LOGGER.debug("The file " + fileNameStored + "was correctly created");
							prepareResponse(resp, fileNameStored, false);
						} else {
							String libelleErreur = "Impossible de sauvegarder le fichier : un justificatif existe deja";
							prepareResponse(resp, libelleErreur, true);
						}
					}
				}
			} catch (Exception e) {
				String libelleErreur = "Error " + HttpServletResponse.SC_INTERNAL_SERVER_ERROR + " occurred while creating the file : " + e.getMessage();
				prepareResponse(resp, libelleErreur, true);
			}
		} else {
			String libelleErreur = "Error " + HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE + ": Request contents type is not supported by the servlet.";
			prepareResponse(resp, libelleErreur, true);
		}
	}

	/**
	 * 
	 * @param resp
	 * @param message
	 * @param isError
	 * @throws IOException
	 */
	private void prepareResponse(HttpServletResponse resp, String message, boolean isError) throws IOException {
		resp.setStatus(HttpServletResponse.SC_CREATED);
		resp.setContentType("text/html");
		resp.setHeader("Pragma", "No-cache");
		resp.setDateHeader("Expires", 0);
		resp.setHeader("Cache-Control", "no-cache");
		PrintWriter out = resp.getWriter();
		if (isError) {
			LOGGER.error("ERROR: " + message);
			out.println("ERROR: " + message);
		} else {
			out.println(message);
		}
		out.flush();
		resp.flushBuffer();
	}

	/**
	 * Generate temporary filename
	 * 
	 * @param idFrais
	 * @param fileNameReceived
	 * @return
	 */
	public String getFileName(String fileNameReceived) {
		LOGGER.debug("FileNameReceived : " + fileNameReceived);
		String dateStr = formatDate(new Date());
		String extension = getFileExtension(fileNameReceived);
		String fileNameStored = dateStr + "." + extension;
		LOGGER.info("FileNameStored : " + fileNameStored);
		return fileNameStored;
	}

	/**
	 * Extract file extension or generate one
	 * 
	 * @param fileNameReceived
	 * @return
	 */
	private String getFileExtension(String fileNameReceived) {
		String[] tabFile = fileNameReceived.split("[.]");
		String extension = null;
		if (tabFile.length == 2) {
			extension = tabFile[1];
		} else {
			extension = "pdf";
		}
		return extension;
	}

	/**
	 * 
	 * @param date
	 * @return
	 */
	private String formatDate(Date date) {
		return FORMAT_DATE.format(date);
	}

	/**
	 * 
	 * @return
	 */
	private File getTempDir() {
		return new File(getWorkingDirectory());
	}

	public String getWorkingDirectory() {
		return StringUtils.isEmpty(workingDirectory) ? DEFAULT_WORKING_DIR : workingDirectory;
	}

	@Override
	public void handleRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		LOGGER.info("Handle Request Spring");
		doPost(req, resp);

	}

	@Override
	public void init(ServletConfig config) throws ServletException {
		SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
		super.init(config);
	}

}
